package Day019_Junit单元测试_NIO.demo4_Channel接口_通道;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

/**
 * @author zhangyan
 * @date 2020/5/12 14:18
 */
/*
            MappedByteBuffer map(MapMode mode, long position, long size);
            说明：将节点中从position开始的size个字节映射到返回的MappedByteBuffer中
                 MapMode:用来指定读或者写的模式

            只有RandomAccessFile获取的Channel才能开启任意的这三种模式
 */
public class Test4_MappedByteBuffer实现高效读写 {
    public static void main(String[] args) throws Exception {

        //复制2GB以上文件(分块复制)

        //1. 创建RandomAccessFile
        // "r" 表示只读--->输入流只读不写
        RandomAccessFile r1 = new RandomAccessFile("Demo02\\aaa\\e.txt","r");
        // "rw" 表示读写--->输出流需要读,写
        RandomAccessFile r2 = new RandomAccessFile("Demo02\\aaa\\eCopy3.txt","rw");

        //2. 获取FileChannel通道对象
        FileChannel c1 = r1.getChannel();
        FileChannel c2 = r2.getChannel();

        //获取文件大小
        long size = c1.size();

        //**********************************************

        // 定义变量:每次复制的字节大小 everySize
        long everySize = 500*1024*1024;

        // 复制的次数: size % everySize == 0? size / everySize : size / everySize + 1
        long count = size % everySize == 0? size / everySize : size / everySize + 1;

        //循环分块复制
        for (long i = 0; i < count; i++) {
            //3. 直接把硬盘的文件映射到内存中(MappedByteBuffer)
            // ***b1默认大小: Integer.MAX_VALUE  2GB***

            //第一次从0字节到500字节
            //第二次从500字节到1000字节
            //......
            //第五次从2500到2800字节
            //position从哪里开始:
            long start = i * everySize;
            //size每次复制的字节数:
            long trueSize = size - start > size? everySize : size - start;

            MappedByteBuffer b1 = c1.map(FileChannel.MapMode.READ_ONLY,start,trueSize);
            MappedByteBuffer b2 = c2.map(FileChannel.MapMode.READ_WRITE,start,trueSize);

            //4. 循环读写数据
            for (int j = 0; j < 10; j++) {
                //获取一个字节
                byte b = b1.get(); // 不需要i,根据缓冲数组读取 根据position读
                //把获取的字节存储到第二个数组中
                b2.put(b);
            }

        }


        //**********************************************

        //5. 关闭资源
        c2.close();
        c1.close();
        r2.close();
        r1.close();
    }


    //复制2GB一下的文件
    private static void method() throws IOException {
        //1. 创建RandomAccessFile
        // "r" 表示只读--->输入流只读不写
        RandomAccessFile r1 = new RandomAccessFile("Demo02\\aaa\\e.txt","r");
        // "rw" 表示读写--->输出流需要读,写
        RandomAccessFile r2 = new RandomAccessFile("Demo02\\aaa\\eCopy2.txt","rw");

        //2. 获取FileChannel对象
        FileChannel c1 = r1.getChannel();
        FileChannel c2 = r2.getChannel();

        //获取文件大小
        long size = c1.size();

        //3. 直接把硬盘的文件映射到内存中(MappedByteBuffer)
        MappedByteBuffer b1 = c1.map(FileChannel.MapMode.READ_ONLY,0,size);
        MappedByteBuffer b2 = c2.map(FileChannel.MapMode.READ_WRITE,0,size);
        //4. 循环读写数据
        for (long i = 0; i < size; i++) {
            //获取一个字节
            byte b = b1.get(); // 不需要i,根据缓冲数组读取 根据position读
            //把获取的字节存储到第二个数组中
            b2.put(b);
        }
        //5. 关闭资源
        c2.close();
        c1.close();
        r2.close();
        r1.close();
    }
}
